﻿using DocumentFormat.OpenXml.Bibliography;
using SanJ.FreeCare.ObservationDefinitionItems;
using SanJ.FreeCare.ObservationDefinitions;
using SanJ.FreeCare.Peis.Configure.DetailPage;
using SanJ.FreeCare.ValueSets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;

namespace SanJ.FreeCare.Peis
{
    public partial class PeisAppService : FreeCareAppService, IPeisAppService
    {
        public async Task<PagedResultDto<DetailDto>> GetDetailListAsync(GetDetailInput input)
        {
            var totalCount = await _observationDefinitionManager.GetCountAsync(input.FilterText);
            var items = await _observationDefinitionManager.GetPageLisAsync(input.FilterText, input.Sorting, input.MaxResultCount, input.SkipCount);
            var obd_ids = items.Select(p => p.Id).ToList();
            var obdItemList = await _observationDefinitionItemManager.GetListByObservationDefinitionIds(obd_ids);

            List<DetailDto> resultItems = new List<DetailDto>();
            foreach (var item in items)
            {
                resultItems.Add(ToDetailDto(item, obdItemList.Where(p => p.ObservationDefinitionId == item.Id).ToList()));
            }
            return new PagedResultDto<DetailDto>
            {
                TotalCount = totalCount,
                Items = resultItems
            };
        }

        public async Task<DetailDto> GetDetailAsync(Guid id)
        {
            var ob = await _observationDefinitionManager.GetByIdAsync(id);
            var obiList = await _observationDefinitionItemManager.GetListByObservationDefinitionId(id);
            return ToDetailDto(ob, obiList);
        }

        public async Task<DetailDto> CreateDetailAsync(DetailCreateDto input)
        {
            ObservationDefinition od = ToObservationDefinition(input);
            var insertedEntity = await _observationDefinitionManager.CreateAsync(od);
            ObservationDefinitionItem odi = ToObservationDefinitionItem(input, insertedEntity.Id);
            var insertedItemEntity = await _observationDefinitionItemManager.CreateAsync(odi);
            List<ObservationDefinitionItem> items = [insertedItemEntity];
            DetailDto result = ToDetailDto(insertedEntity, items);
            return result;
        }


        public async Task<DetailDto> UpdateDetailAsync(DetailUpdateDto input)
        {
            ObservationDefinition od = ToObservationDefinition(input);
            var updatedEntity = await _observationDefinitionManager.UpdateAsync(input.Id, od);
            await _observationDefinitionItemManager.DeleteByObdIdAsync(input.Id);
            ObservationDefinitionItem odi = ToObservationDefinitionItem(input, updatedEntity.Id);
            var insertedItemEntity = await _observationDefinitionItemManager.CreateAsync(odi);
            List<ObservationDefinitionItem> items = [insertedItemEntity];
            var result = ToDetailDto(updatedEntity, items);
            return result;
        }

        public Task DeleteDetailAsync(Guid id)
        {
            _observationDefinitionItemManager.DeleteByObdIdAsync(id);
            return _observationDefinitionManager.Delete(id);
        }

        private DetailDto ToDetailDto(ObservationDefinition source, List<ObservationDefinitionItem> sourceItem)
        {
            DetailDto result = new DetailDto();
            result.DetailItems = new List<DetailItemDto>();
            result.Id = source.Id;
            result.Name = source.Name;
            result.Spell = source.Spell;
            result.Description = source.Description;
            result.DataType = source.PermittedDataType;
            result.Category = source.Category;
            result.UiControlType = source.UiControlType;
            result.PermittedUnit = source.PermittedUnit;
            result.PreferredReportName = source.PreferredReportName;
            result.Description = source.Description;
            result.DisplayOrder = source.DisplayOrder;

            result.DetailItems = new List<DetailItemDto>();
            foreach (var item in sourceItem)
            {
                if (item != null && !item.NormalConcepts.IsNullOrEmpty() && item.Context == ObservationContext.PeisDetial)
                {
                    var codeList = JsonSerializer.Deserialize<List<CodeConcept>>(item.NormalConcepts);
                    if (codeList != null)
                    {
                        foreach (var code in codeList)
                        {
                            DetailItemDto detailItem = new DetailItemDto();
                            detailItem.NormalCode = code.Display;
                            detailItem.DisplayOrder = code.DisplayOrder;
                            result.DetailItems.Add(detailItem);
                        }
                    }
                }
            }
            return result;
        }

        private ObservationDefinition ToObservationDefinition(DetailCreateDto input)
        {
            ObservationDefinition od = new ObservationDefinition();
            od.Name = input.Name;
            od.Spell = input.Spell;
            string[] dateTypes = new string[1];
            dateTypes[0] = input.DataType;
            od.PermittedDataType = JsonSerializer.Serialize(dateTypes);
            string[] units = new string[1];
            units[0] = input.UnitCode;
            od.PermittedUnit = JsonSerializer.Serialize(units);
            od.Category = input.Category;
            od.DisplayOrder = input.DisplayOrder;
            return od;
        }

        private ObservationDefinitionItem ToObservationDefinitionItem(DetailCreateDto input, Guid odId)
        {
            ObservationDefinitionItem odi = new ObservationDefinitionItem();
            odi.ObservationDefinitionId = odId;
            odi.Context = ObservationContext.PeisDetial;
            odi.RangMin = input.RangMin;
            odi.RangMax = input.RangMax;
            if (input.DetailItems != null && input.DetailItems.Count > 0)
            {
                List<CodeConcept> codes = new List<CodeConcept>();
                foreach (var item in input.DetailItems)
                {

                    CodeConcept concept = new CodeConcept();
                    concept.Display = item.NormalCode;
                    concept.DisplayOrder = item.DisplayOrder;
                    codes.Add(concept);
                }
                odi.NormalConcepts = JsonSerializer.Serialize(codes); ;
            }

            return odi;
        }
    }
}
